package com.angus.modules.content.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.angus.api.front.domain.FrontUser;
import com.angus.common.core.enums.PayMethod;
import com.angus.common.core.utils.ip.IpUtils;
import com.angus.common.security.config.QixiangConfig;
import com.angus.api.content.domain.OrderCommission;
import com.angus.modules.content.domain.SysOrder;
import com.angus.modules.content.dto.OrderPayDto;
import java.time.LocalDateTime;
import com.angus.modules.content.mapper.FrontUserMapper;
import com.angus.modules.content.repository.OrderCommissionRepository;
import com.angus.modules.content.repository.SysOrderRepository;
import com.angus.modules.content.service.QixiangPayService;
import com.angus.modules.content.vo.QixiangPayVo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.RoundingMode;
import java.util.*;


/**
 * @author linCode
 */
@Service
public class QixiangPayServiceImpl implements QixiangPayService {

    private static final Logger log = LoggerFactory.getLogger(QixiangPayServiceImpl.class);

    private static final String DEVICE = "jump";
    private static final String SING_TYPE = "MD5";

    @Resource
    private QixiangConfig qixiangConfig;

    @Resource
    private SysOrderRepository sysOrderRepository;

    @Resource
    private OrderCommissionRepository orderCommissionRepository;

    @Resource
    private FrontUserMapper frontUserMapper;

    @Override
    public QixiangPayVo qixiangPay(OrderPayDto dto, Long userId) {

        SysOrder order = sysOrderRepository.getOrderByOrderNo(dto.getOrderNo(), userId);
        if(Objects.isNull(order)){
            QixiangPayVo qixiangPayVo = new QixiangPayVo();
            qixiangPayVo.setCode(-999);
            qixiangPayVo.setMsg("订单不存在");
            return qixiangPayVo;
        }

        Map<String,Object> params = new HashMap<>();

        params.put("pid",qixiangConfig.getMchId());
        params.put("type", PayMethod.fromFlag(dto.getPayMethod()));
        params.put("out_trade_no",dto.getOrderNo());
        params.put("notify_url",qixiangConfig.getNotifyUrl());
        params.put("return_url", dto.getReturnUrl());
        params.put("name",order.getCourseName());
        params.put("money",order.getCourseAmount().setScale(2, RoundingMode.HALF_UP).toString());
        params.put("clientip", IpUtils.getIpAddr());
        params.put("device", DEVICE);
        String sign = generateSign(params, qixiangConfig.getMchKey());
        params.put("sign", sign);
        params.put("sign_type", SING_TYPE);

        log.info("QixiangPayServiceImpl.qixiangPay params:{}",params);

        String result = HttpUtil.post(qixiangConfig.getPayUrl(), params);

        return JSONUtil.toBean(result, QixiangPayVo.class);
    }

    @Override
    public String qixiangNotify(HttpServletRequest request) {
        // 检查交易状态是否为成功
        if (!"TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
            // 如果状态不是成功，则返回失败
            return "failure";
        }
        // 创建一个存储请求参数的Map
        Map<String, String> params = getRequestParams(request);
        // 提取支付信息
        // 订单号
        String tradeNo = params.get("out_trade_no");
        SysOrder order = sysOrderRepository.getOrder(tradeNo);
        if(Objects.nonNull(order)){
            // 更新订单信息
            sysOrderRepository.updateOrderStatus(tradeNo, order.getValidDays());
            // 更新用户信息：付费用户
            FrontUser frontUser = frontUserMapper.selectById(order.getUserId());
            frontUser.setUserType(2);
            frontUser.setUpdateTime(LocalDateTime.now());
            frontUserMapper.updateById(frontUser);
            // 推荐人奖励
            if (StringUtils.isNotBlank(order.getRecommendCode())){
                // 查询推荐人信息
                FrontUser recommendUser = frontUserMapper.selectOne(Wrappers.lambdaQuery(FrontUser.class)
                        .eq(FrontUser::getRecommendCode, order.getRecommendCode())
                        .eq(FrontUser::getDelFlag, 0));
                //生成要转账佣金记录
                OrderCommission orderCommission = new OrderCommission();
                orderCommission.setOrderNo(tradeNo);
                orderCommission.setUserId(recommendUser.getUserId());
                orderCommission.setCourseCode(order.getCourseCode());
                orderCommission.setCourseAmount(order.getCourseAmount());
                orderCommission.setRecommendCode(recommendUser.getRecommendCode());
                orderCommission.setCommissionRate(order.getCommissionRate());
                orderCommission.setCommissionAmount(order.getCourseAmount().multiply(order.getCommissionRate()));
                orderCommissionRepository.save(orderCommission);
            }
        }
        return "success";
    }

    private String generateSign(Map<String, Object> params, String key) {
        Map<String, String> filteredParams = new TreeMap<>();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            filteredParams.put(entry.getKey(), entry.getValue().toString());
        }

        // 拼接参数
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : filteredParams.entrySet()) {
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(entry.getKey()).append("=").append(entry.getValue());
        }
        // 拼接商户密钥
        sb.append(key);
        // MD5加密
        return cn.hutool.crypto.digest.DigestUtil.md5Hex(sb.toString());
    }


    /**
     * 提取请求参数的方法
     */
    private Map<String, String> getRequestParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            params.put(name, request.getParameter(name));
        }
        return params;
    }


}
